Skip to content

report a cancelled ctx read as the deadline, not end-of-stream - #595

Merged
kacy merged 1 commit into
mainfrom
read-exact-ctx-deadline
Jul 26, 2026
Merged

report a cancelled ctx read as the deadline, not end-of-stream#595
kacy merged 1 commit into
mainfrom
read-exact-ctx-deadline

Conversation

@kacy

@kacy kacy commented Jul 26, 2026

Copy link
Copy Markdown
Owner

summary

a deadline-limited read on a subprocess pipe spawns a worker to do the read and
polls the context's cancel flag while waiting. under a single green worker the
worker can finish the same instant the deadline fires — task.is_done() wins
the poll before the cancel is seen — so a read that came back empty only because
it would have blocked was returned as a clean end-of-stream. read_exact then
failed with "unexpected eof" instead of deadline-exceeded, and read_all would
stop a chunk short.

after awaiting the worker, the four process read primitives re-check the
context: if it is cancelled and nothing was read, that empty is the deadline,
not eof. real data read before the deadline is kept — only an empty-or-errored
result is reclassified, so no data is dropped. the tcp read path already checked
the cancel before reading and is unchanged.

how it was found

verify-green-corpus (the corpus-under-green harness added in #594) caught it:
test_process_ctx diverged under one worker only, correct at the default worker
count and os threads. with this fix it matches on all three, so its entry in
GREEN_CORPUS_EXCLUDE is removed and the whole corpus — 260 cases, both green
worker modes — is byte-identical to os-thread again.

what was tested

make verify-green-corpus at 260/260 (both worker modes, exclude removed),
make bootstrap-verify green, make green-tests, make memcheck clean under
valgrind. test_process_ctx verified matching its expected output under os
threads, green default workers, and green single worker.

notes

std-only change; the process io/tcp/command regression cases are unaffected
(verified). this is the one green correctness gap the corpus harness surfaced —
part of the green-default-flip prerequisites.

a deadline-limited read on a subprocess pipe spawns a worker to do the read and
polls the context's cancel flag while waiting. under a single green worker the
worker can finish the same instant the deadline fires: `task.is_done()` then
wins the poll before the cancel is seen, so a read that came back empty only
because it would have blocked was returned as a clean end-of-stream. a
`read_exact` on top of it then failed with "unexpected eof" instead of
deadline-exceeded, and `read_all` would stop short a chunk early.

after awaiting the worker, the four process read primitives now re-check the
context: if it is cancelled and nothing was read, that empty is the deadline,
not eof. a read that returned real data before the deadline keeps it — only an
empty-or-errored result is reclassified, so no data is dropped. the tcp read
path already checked the cancel before reading and needed no change.

found by verify-green-corpus: test_process_ctx diverged under one worker only
(correct at the default worker count and os-thread). it now matches on all
three, so its exclusion is removed and the whole corpus — 260 cases, both green
worker modes — is byte-identical to os-thread again.
@kacy
kacy merged commit edcbbbf into main Jul 26, 2026
2 checks passed
@kacy
kacy deleted the read-exact-ctx-deadline branch July 26, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant